﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;

namespace wontec_claw
{
    class UART2CAN
    {
        public Action<List<byte[]>> dataRecv;
        public Action<List<byte>> COM_DataReceived;
        public Action<byte[]> dataSend;
        public Action<SerialPort> setCOM;
        public Action<int> SetBPS;
        SerialPort COM;

        List<byte[]> dataBuff = new List<byte[]>();
        byte[] canData = { 0x55, 0xAA, 0x1E, 0x03, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 };

        private byte CRC_8(byte[] source, int offset, int len)
        {
            byte b = 0;
            int num = 0;
            while (len-- != 0)
            {
                b ^= source[num];
                num++;
                for (int i = 0; i < 8; i++)
                {
                    bool flag = (b & 1) == 1;
                    if (flag)
                    {
                        b = (byte)(b >> 1 ^ 140);
                    }
                    else
                    {
                        b = (byte)(b >> 1);
                    }
                }
            }
            return b;
        }

        int step = 0;
        int flag = 0;
        int stats = 0;
        int len = 0;
        public int canid = 0;
        public byte[] candata = new byte[12];
        long ticks;
        public void candecode(List<byte> canBuffer)
        {
            if (true)
            {
                if (System.DateTime.Now.Ticks > ticks)
                    step = 0;
                while (canBuffer.Count != 0)
                {
                    int dat = canBuffer[0]; canBuffer.RemoveAt(0);
                    ticks = System.DateTime.Now.Ticks + 50 * 10000;
                    switch (step)
                    {
                        case 0:
                            if (dat == 0xAA)
                                step++;
                            break;
                        case 1:
                            flag = dat;
                            step++;
                            break;
                        case 2:
                            stats = dat;
                            step++;
                            len = 0;
                            break;
                        
                        case 3:
                            if (len != 12)
                            {
                                candata[len] = (byte)dat;
                                len++;
                                if (len == 12) step++;
                            }
                            break;
                        case 4:
                            step = 0;
                            if (dat == 0x55)
                            {
                                var data = new byte[12];
                                for (int i = 0; i < 8; i++)
                                    data[i] = candata[i+4];
                                for (int i = 0; i < 4; i++)
                                    data[i+8] = candata[i];
                                dataBuff.Add(data);
                                //return this[canid, candata];
                                //if (callback != null) callback(info);
                            }
                            break;
                    }
                }
                //System.Threading.Thread.Sleep(0);
            }
            //return null;
        }

        public UART2CAN()
        {
            dataRecv = (List<byte[]> data) => {
                dataBuff = data;
            };
            dataSend = (byte[] data) => {
                var bytes = new byte[canData.Length];
                int offset = 0;
                for (int i = 0; i < canData.Length; i++)
                    bytes[i + offset] = canData[i];

                bytes[offset + 13] = data[8];
                bytes[offset + 14] = data[9];
                bytes[offset + 15] = data[10];
                bytes[offset + 16] = data[11];

                for (int i = 0; i < 8; i++)
                {
                    bytes[offset + 21 + i] = data[i];
                }

                bytes[offset + canData.Length - 1] = CRC_8(bytes, offset, canData.Length);
                //offset += canData.Length;
                if (COM == null) return;
                if (!COM.IsOpen) return;
                COM.Write(bytes, 0, bytes.Length);
            };
            setCOM = (SerialPort com) => { COM = com; };
            COM_DataReceived = candecode;
            List<int> canbps = new List<int>(new int[] { 1000, 800, 666, 500, 400, 250, 200, 125, 100, 80, 50, 40, 20, 10 });
            SetBPS = (int value) =>
             {
                 if (COM == null) return;
                 if (!COM.IsOpen) return;
                 var index = canbps.IndexOf(value);
                 var setbps = new byte[] { 0x55, 0x05, (byte)index, 0xaa, 0x55 };
                 COM.Write(setbps, 0, setbps.Length);
             };


        }
    }
}
